<?php


namespace models\Business;


use models\DAO\TurnoverModel;
use models\Exception\Business\AccountException;
use models\Exception\Business\MemberException;
use models\Exception\Business\TurnoverException;
use models\Exception\Business\UserException;
use models\Exception\Business\WithdrawException;
use models\Exception\DAO\ModelDriverException;
use models\Exception\DAO\ModelException;
use models\Exception\DAO\ModelReflectionException;
use models\Exception\DAO\ModelSqlException;
use models\Exception\Service\ServiceException;
use models\Exception\Transformer\TransformerException;
use models\Service\AccountService;
use models\Service\MemberService;
use models\Service\TurnoverService;
use models\Service\UserService;
use models\Service\WithdrawService;
use Yaf\Registry;
use youliPhpLib\Common\PwdAss;
use youliPhpLib\Common\StringOperation;

class Finance
{
    const INTEGRAL_TO_BALANCE_COEFFICIENT = 0.8;

    // 金币转余额 余额转金币时的type的值
    const EXCHANGE_ALLOWED_TYPE_ARR = [3];
    // 提现时的type的值
    const WITHDRAW_ALLOWED_TYPE_ARR = [5];

    // 前台用户获取金币流水、余额流水、全部流水、提现申请记录的type有效值数组
    const TURNOVER_LIST_4_API = [0, 1, 2, 3, 5];

    // 提现申请有效状态数组
    const TURNOVER_VALID_STATS_ARR = [0, 1, 2];

    // 提现订单状态查询时的有效提现订单状态数组
    const WITHDRAW_QUERY_VALID_STATS_ARR = [1];

    // 提现有效通道
    const WITHDRAW_TYPE = ['AliPay'];

    // 金豆流水页面的几个转改
    const INTEGRAL_TURNOVER_TYPE = [
        [
            'id' => 10,
            'name' => '流单',
            'key' => 4
        ],
        /*[
            'id' => 9,
            'name' => '进行中',
            'key' => 3
        ],*/
        [
            'id' => 6,
            'name' => '兑换',
            'key' => 2
        ],
        [
            'id' => 5,
            'name' => '获得记录',
            'key' => 1
        ],
        [
            'id' => 8,
            'name' => '全部',
            'key' => 0
        ],
    ];
    const BALANCE_TURNOVER_TYPE = [
        [
            'id' => 7,
            'name' => '拼单支付',
            'key' => 5
        ],
        [
            'id' => 4,
            'name' => '拼单退回',
            'key' => 4
        ],
        [
            'id' => 3,
            'name' => '提现',
            'key' => 3
        ],
        [
            'id' => 2,
            'name' => '淘宝',
            'key' => 2
        ],
        [
            'id' => 1,
            'name' => '兑换',
            'key' => 1
        ],
        [
            'id' => 0,
            'name' => '全部',
            'key' => 0
        ],
    ];

    /**
     * 审核余额提现记录
     * @param array $parameters
     * @return bool
     * @throws AccountException
     * @throws MemberException
     * @throws ModelSqlException
     * @throws TurnoverException
     * @throws UserException
     * @throws WithdrawException
     */
    static public function reviewWithdraw($parameters = []) {
        $model = TurnoverModel::getInstance();
        $conn = $model->getConn();
        $conn->beginTransaction();
        try {
            if (isset($parameters['from_api']) && $parameters['from_api'] === true)
                throw new TurnoverException(TurnoverException::TURNOVER_DENIED, TurnoverException::TURNOVER_DENIED_NO);

            if (! isset($parameters['id']) || empty($parameters['id']))
                throw new TurnoverException(TurnoverException::TURNOVER_ID_IS_EMPTY, TurnoverException::TURNOVER_ID_IS_EMPTY_NO);

            $update_turnover_arr = $account_info = [];
            $create_withdraw_order = $refuse_withdraw = false;
            $create_withdraw_order_sql = $withdraw_channel_class = $withdraw_order_sn = null;

            // 查询提现流水
            $turnover_info = TurnoverService::getInstance()->getOne($parameters['id']);

            if (!isset($parameters['stats']) || (isset($parameters['stats']) && ! in_array($parameters['stats'], self::TURNOVER_VALID_STATS_ARR))) {
                throw new TurnoverException(TurnoverException::INVALID_STATS, TurnoverException::INVALID_STATS_NO);
            }

            // 审核通过 创建提现订单
            if ($parameters['stats'] == 1)
                $create_withdraw_order = true;
            else if ($parameters['stats'] == 2)
                $refuse_withdraw = true;

            // 读取当前后台操作者的信息
            $user_info = UserService::getInstance()->getOne(Registry::get('jwt_info')->id);
            if (empty($user_info))
                throw new UserException(UserException::USER_IS_NOT_EXISTS, 401);

            array_push($update_turnover_arr, "`stats` = '" . $parameters['stats'] . "'");
            array_push($update_turnover_arr, "`remark` = '" . ($turnover_info['remark'] . $user_info['mobile'] . "于" . date("Y-m-d H:i:s", time()) .
                    "完成审核。审核状态为:" . ($parameters['stats'] == 2 ? "拒绝" : ($parameters['stats'] == 1 ? "通过" : "未审核"))) . "\r\n'");
            array_push($update_turnover_arr, "`updated_by` = '" . Registry::get('jwt_info')->id . "'");
            $update_turnover_sql = "UPDATE `turnover` SET " . implode(',', $update_turnover_arr) .
                " WHERE `id` = '" . $parameters['id'] . "'";
            Registry::get('db_log')->info("后台通过提现，提现记录.sql: " . $update_turnover_sql);
            $conn->executeQuery($update_turnover_sql);


            // 提现申请被拒绝 归还余额
            if ($refuse_withdraw === true) {
                $member = MemberService::getInstance()->getOne($turnover_info['member_id']);
                if (empty($member))
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);

                // 新增一条归还余额的流水记录
                $sql = "INSERT INTO `turnover` (`type`, `member_id`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                    "VALUE ('4', '" . $member['id'] . "', '1', '拒绝提现，归还余额', '" . $member['balance'] . "', '" . abs($turnover_info['amount']) . "', '" . ($member['balance'] + abs($turnover_info['amount'])) . "')";
                Registry::get('db_log')->info("后台拒绝提现，归还余额sql: " . $sql);
                $conn->executeQuery($sql);

                // 归还余额
                $update_member = "UPDATE `member` SET `balance` = `balance` + " . abs($turnover_info['amount']) . " WHERE `id` = '" . $member['id'] . "'";
                Registry::get('db_log')->info("归还member的sql: " . $sql);
                $conn->executeQuery($update_member);

                $conn->commit();

                return true;
            }

            // 创建提现订单
            if ($create_withdraw_order === true) {
                // 查询提现账号 获取提现通道
                $account_info = AccountService::getInstance()->getOne($turnover_info['account_id']);

                $withdraw_order_sn = StringOperation::genOrderSn();

                // 计算实际到账金额
                $withdraw_rate = 0.02;
                $amount = (1 - $withdraw_rate) * abs($turnover_info['amount']);

                // 生成提现订单sql
                $create_withdraw_order_sql = "INSERT INTO `withdraw` (`sn`, `member_id`, `account_id`, `turnover_id`, `amount`, `type`, `stats`, `remark`, `created_by`) " .
                    "VALUES ('" . $withdraw_order_sn . "', '" . $turnover_info['member_id'] . "', '" . $turnover_info['account_id'] .
                    "', '" . $parameters['id'] . "', '" . $amount/*abs($turnover_info['amount'])*/ . "', '" . $account_info['type'] . "', '0', '', '" . Registry::get('jwt_info')->id . "')";
            }

            // 提现账号信息查询失败
            if (empty($account_info)) {
                throw new AccountException(AccountException::ACCOUNT_IS_NOT_EXISTS, AccountException::ACCOUNT_IS_NOT_EXISTS_NO);
            }
            // 提现账号信息查询成功 创建提现订单sql生成失败
            else if (! empty($account_info) && is_null(is_null($create_withdraw_order_sql))) {
                throw new WithdrawException(WithdrawException::WITHDRAW_CREATE_SQL_GENERATE_FAILURE, WithdrawException::WITHDRAW_CREATE_SQL_GENERATE_FAILURE_NO);
            }
            // 提现账号信息查询成功 创建提现订单sql生成成功
            else {
                Registry::get('db_log')->info("后台创建提现订单.sql: " . $create_withdraw_order_sql);
                $conn->executeQuery($create_withdraw_order_sql);
            }

            $conn->commit();

            // 提现订单创建成功 发起接口调用
            if (! is_null($withdraw_order_sn)) {
                $withdraw_channel_arr = self::WITHDRAW_TYPE;
                if (! isset($withdraw_channel_arr[$account_info['type']]))
                    throw new WithdrawException(WithdrawException::INVALID_CHANNEL, WithdrawException::INVALID_CHANNEL_NO);
                else if ($withdraw_channel_arr[$account_info['type']] === 'AliPay') {
                    $withdraw_channel_class = AliPay::class;
                }
                Registry::get('db_log')->info("提现订单创建成功.订单编号: " . $withdraw_order_sn);
            }

            $result = null;
            if (is_null($withdraw_channel_class))
                throw new WithdrawException(WithdrawException::THERE_IS_NOT_AVAILABLE_CLASS, WithdrawException::THERE_IS_NOT_AVAILABLE_CLASS_NO);
            /*else if (method_exists($withdraw_channel_class, 'asyncWithdraw'))
                $result = $withdraw_channel_class::asyncWithdraw($withdraw_order_sn, $account_info['account'], $account_info['name'], abs($turnover_info['amount']));
            else if (method_exists($withdraw_channel_class, 'delayWithdraw'))
                $result = $withdraw_channel_class::delayWithdraw($withdraw_order_sn, $account_info['account'], $account_info['name'], abs($turnover_info['amount']));*/
            else if (method_exists($withdraw_channel_class, 'withdraw'))
                $result = $withdraw_channel_class::Withdraw($withdraw_order_sn, $account_info['account'], $account_info['name'], $amount/*abs($turnover_info['amount'])*/);
            else
                throw new WithdrawException(WithdrawException::THERE_IS_NOT_AVAILABLE_METHOD, WithdrawException::THERE_IS_NOT_AVAILABLE_METHOD_NO);

            if (is_null($result) || !isset($result['status']))
                throw new WithdrawException(WithdrawException::WITHDRAW_FAILURE, WithdrawException::WITHDRAW_FAILURE_NO);

            WithdrawService::getInstance()->update(['stats' => (int)($result['status'] === 'SUCCESS' ? 3 : 0), 'out_trade_no' => $result['order_id'],
                'notified_at' => date('Y-m-d H:i:s', time())], $withdraw_order_sn);

            // 推送消息
            JPush::withdrawPush($withdraw_order_sn, 'success');

            return true;

        } catch (UserException $e) {
            throw $e;
        } catch (MemberException $e) {
            throw $e;
        } catch (WithdrawException $e) {
            throw $e;
        } catch (TurnoverException $e) {
            throw $e;
        } catch (AccountException $e) {
            throw $e;
        } catch (\Exception $e) {
            $conn->rollback();
            throw new TurnoverException(TurnoverException::WITHDRAW_REVIEW_FAILURE, TurnoverException::WITHDRAW_REVIEW_FAILURE_NO);
        }

    }

    /**
     * 查询指定提现订单的上游订单状态
     * @param array $parameters
     * @return array|mixed|null
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TransformerException
     * @throws WithdrawException
     */
    static public function queryWithdrawOrderStats($parameters = []) {
        try {
            if (! isset($parameters['id']) || empty($parameters['id']))
                throw new WithdrawException(WithdrawException::WITHDRAW_ID_IS_EMPTY, WithdrawException::WITHDRAW_ID_IS_EMPTY_NO);

            if (! isset($parameters['stats']) || ! in_array($parameters['stats'], self::WITHDRAW_QUERY_VALID_STATS_ARR))
                throw new WithdrawException(WithdrawException::INVALID_STATS, WithdrawException::INVALID_STATS_NO);

            $withdraw = WithdrawService::getInstance()->getOne(['groupOp' => 'AND', 'rules' => [
                ['field' => 'sn', 'op' => 'eq', 'data' => $parameters['id']],
                ['field' => 'stats', 'op' => 'eq', 'data' => $parameters['stats']]
            ]]);

            if (empty($withdraw))
                throw new WithdrawException(WithdrawException::WITHDRAW_IS_NOT_EXISTS, WithdrawException::WITHDRAW_IS_NOT_EXISTS_NO);

            if (empty($withdraw['out_trade_no']))
                throw new WithdrawException(WithdrawException::WITHDRAW_NO_OUT_TRADE_NO, WithdrawException::WITHDRAW_NO_OUT_TRADE_NO_NO);

            $withdraw_channel_class = $res = null;
            $withdraw_channel_arr = self::WITHDRAW_TYPE;
            if (! isset($withdraw_channel_arr[$withdraw['type']]))
                throw new WithdrawException(WithdrawException::INVALID_CHANNEL, WithdrawException::INVALID_CHANNEL_NO);
            else if ($withdraw_channel_arr[$withdraw['type']] === 'AliPay')
                $withdraw_channel_class = AliPay::class;

            if (is_null($withdraw_channel_class))
                throw new WithdrawException(WithdrawException::THERE_IS_NOT_AVAILABLE_CLASS, WithdrawException::THERE_IS_NOT_AVAILABLE_CLASS_NO);
            else if (method_exists($withdraw_channel_class, 'withdraw'))
                $res = $withdraw_channel_class::QueryWithdraw($withdraw['out_trade_no']);
            else
                throw new WithdrawException(WithdrawException::THERE_IS_NOT_AVAILABLE_QUERY_METHOD, WithdrawException::THERE_IS_NOT_AVAILABLE_QUERY_METHOD_NO);

            // 查询成功 更新订单状态
            if ($res !== null)
                $withdraw = WithdrawService::getInstance()->update(['stats' => $res['stats']], $parameters['id']);

            return $withdraw;
        } catch (WithdrawException $e) {
            throw $e;
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new WithdrawException(WithdrawException::WITHDRAW_EDIT_FAILURE, WithdrawException::WITHDRAW_EDIT_FAILURE_NO);
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    /**
     * 获取提现订单列表
     * @param array $parameters
     * @return array|mixed
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TransformerException
     */
    static public function getWithdrawOrders($parameters = []) {
        try {
            $rules = $condition = [];
            if (isset($parameters['stats']))
                array_push($rules, ['field' => 'stats', 'op' => 'eq', 'data' => $parameters['stats']]);

            if (isset($parameters['type']))
                array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => $parameters['type']]);

            if (isset($parameters['sn']))
                array_push($rules, ['field' => 'sn', 'op' => 'eq', 'data' => $parameters['sn']]);

            $member_id_arr = [];
            if (isset($parameters['mobile'])) {
                $member = MemberService::getInstance()->getList(1, 999, 'desc', 'id', ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'mobile', 'op' => 'nc', 'data' => $parameters['mobile'] . '%']]]);
                if (! empty($member['data']))
                    $member_id_arr = array_column($member['data'], 'id');
                else
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
            }

            if (isset($parameters['nickname'])) {
                $member = MemberService::getInstance()->getList(1, 999, 'desc', 'id', ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'nickname', 'op' => 'nc', 'data' => $parameters['nickname'] . '%']]]);
                if (! empty($member['data']))
                    $member_id_arr = empty($member_id_arr) ? array_column($member['data'], 'id') :
                        array_merge($member_id_arr, array_column($member['data'], 'id'));
                else
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
            }

            if (isset($parameters['account'])) {
                $account = AccountService::getInstance()->getList(1, 999, 'desc', 'id', ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'account', 'op' => 'nc', 'data' => $parameters['account'] . '%']]]);
                if (! empty($account['data']))
                    $member_id_arr = empty($member_id_arr) ? array_column($account['data'], 'member_id') :
                        array_merge($member_id_arr, array_column($account['data'], 'member_id'));
                else
                    throw new AccountException(AccountException::ACCOUNT_IS_NOT_EXISTS, AccountException::ACCOUNT_IS_NOT_EXISTS_NO);
            }

            if (!empty($member_id_arr))
                array_push($rules, ['field' => 'member_id', 'op' => 'in', 'data' => implode(',', $member_id_arr)]);

            if (isset($parameters['start_created_at']))
                array_push($rules, ['field' => 'created_at', 'op' => 'ge', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['start_created_at'])))]);

            if (isset($parameters['end_created_at']))
                array_push($rules, ['field' => 'created_at', 'op' => 'le', 'data' => date("Y-m-d 23:59:59", strtotime(str_replace('/', '-', $parameters['end_created_at'])))]);

            if (! empty($rules))
                $condition = ['groupOp' => 'AND', 'rules' => $rules];

            $withdraws = WithdrawService::getInstance()->getList(
                isset($parameters['page']) ? $parameters['page'] : 1,
                isset($parameters['page_size']) ? $parameters['page_size'] : 10,
                isset($parameters['sort']) ? $parameters['sort'] : 'desc',
                isset($parameters['order']) ? $parameters['order'] : 'sn',
                $condition
            );

            if (!isset($parameters['from_api']) || $parameters['from_api'] !== false) {
                $withdraws = User::getUsersByModule($withdraws);
                $withdraws = Account::getAccountsByModules($withdraws);
                $withdraws = Member::getMembersByModules($withdraws);
            }

            return $withdraws;
        } catch (ModelDriverException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    /**
     * 获取资金流水记录
     * @param array $parameters
     * @return array|mixed
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TransformerException
     * @throws TurnoverException
     */
    static public function getWithdrawList($parameters = []) {
        try {
            $get_withdraw_order = false;
            $rules = $condition = [];
            if (isset($parameters['from_api']) && $parameters['from_api'] === true) {
                array_push($rules, ['field' => 'member_id', 'op' => 'eq', 'data' => Registry::get('jwt_info')->id]);
                // 余额流水页面，获取全部有关余额的流水记录
                if ($parameters['type'] == 0) {
                    array_push($rules, ['field' => 'type', 'op' => 'in', 'data' => '3,4,5,6,7,8']);
                }
                // 余额流水页面，获取金豆兑换余额的流水记录
                else if ($parameters['type'] == 1) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '3']);
                }
                // 余额流水页面，获取"淘宝"的流水类型 即获得晒单返利流水记录
                else if ($parameters['type'] == 2) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '6']);
                }
                // 余额流水页面，获取余额提现的流水记录
                else if ($parameters['type'] == 3) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '5']);
                }
                // 金豆流水页面，获取全部有关金豆的流水记录
                else if ($parameters['type'] == 8) {
                    array_push($rules, ['field' => 'type', 'op' => 'in', 'data' => '0,2']);
                }
                // 金豆流水页面，获取用户获得金豆的流水记录
                else if ($parameters['type'] == 5) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '0']);
                }
                // 金豆流水页面，获取用户使用金豆兑换商品的流水记录
                else if ($parameters['type'] == 9) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '1']);
                }
                // 金豆流水页面，获取用户"进行中"金豆的流水记录
                else if ($parameters['type'] == 6) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '2']);
                }
                // 金豆流水页面，获取用户流单的的流水记录
                else if ($parameters['type'] == 10) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '0']);
                }
                // 金豆流水页面，获取用户流单的的流水记录
                else if ($parameters['type'] == 4) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '4']);
                }
                // 金豆流水页面，获取用户流单的的流水记录
                else if ($parameters['type'] == 7) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => '7']);
                }
                /*if (! isset($parameters['type']) || ! in_array($parameters['type'], self::TURNOVER_LIST_4_API))
                    throw new TurnoverException(TurnoverException::TURNOVER_LIST_DENIED, TurnoverException::TURNOVER_LIST_DENIED_NO);
                array_push($rules, ['field' => 'member_id', 'op' => 'eq', 'data' => Registry::get('jwt_info')->id]);
                if ($parameters['type'] == 0) {
                    array_push($rules, ['field' => 'type', 'op' => 'in', 'data' => '0,1,2,3,4']);
                } else if ($parameters['type'] == 1) {
                    array_push($rules, ['field' => 'type', 'op' => 'in', 'data' => '0,1,2']);
                } else if ($parameters['type'] == 2) {
                    array_push($rules, ['field' => 'type', 'op' => 'in', 'data' => '3,4,5']);
                } else if (in_array($parameters['type'],[3,4,5])) {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => $parameters['type']]);
                    $get_withdraw_order = true;
                }*/
                unset($parameters['type']);
            } else {
                if ($parameters['type'] == 999) {
                    array_push($rules, ['field' => 'type', 'op' => 'in', 'data' => '0,1,2']);
                } else if ($parameters['type'] == 998) {
                    array_push($rules, ['field' => 'type', 'op' => 'in', 'data' => '3,4']);
                } else if ($parameters['type'] == 997) {
                    array_push($rules, ['field' => 'type', 'op' => 'in', 'data' => '5']);
                } else {
                    array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => $parameters['type']]);
                }
                unset($parameters['type']);
            }

            if (isset($parameters['type']))
                array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => $parameters['type']]);

            if (isset($parameters['stats']))
                array_push($rules, ['field' => 'stats', 'op' => 'eq', 'data' => $parameters['stats']]);

            $member_id_arr = [];
            if (isset($parameters['mobile'])) {
                $member = MemberService::getInstance()->getList(1, 999, 'desc', 'id', ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'mobile', 'op' => 'nc', 'data' => $parameters['mobile'] . '%']]]);
                if (! empty($member['data']))
                    $member_id_arr = array_column($member['data'], 'id');
                else
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
            }

            if (isset($parameters['nickname'])) {
                $member = MemberService::getInstance()->getList(1, 999, 'desc', 'id', ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'nickname', 'op' => 'nc', 'data' => $parameters['nickname'] . '%']]]);
                if (! empty($member['data']))
                    $member_id_arr = empty($member_id_arr) ? array_column($member['data'], 'id') :
                        array_merge($member_id_arr, array_column($member['data'], 'id'));
                else
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
            }

            if (isset($parameters['account'])) {
                $account = AccountService::getInstance()->getList(1, 999, 'desc', 'id', ['groupOp' => 'AND', 'rules' => [
                    ['field' => 'account', 'op' => 'nc', 'data' => $parameters['account'] . '%']]]);
                if (! empty($account['data']))
                    $member_id_arr = empty($member_id_arr) ? array_column($account['data'], 'member_id') :
                        array_merge($member_id_arr, array_column($account['data'], 'member_id'));
                else
                    throw new AccountException(AccountException::ACCOUNT_IS_NOT_EXISTS, AccountException::ACCOUNT_IS_NOT_EXISTS_NO);
            }

            if (!empty($member_id_arr))
                array_push($rules, ['field' => 'member_id', 'op' => 'in', 'data' => implode(',', $member_id_arr)]);

            if (isset($parameters['start_created_at']))
                array_push($rules, ['field' => 'created_at', 'op' => 'ge', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['start_created_at'])))]);

            if (isset($parameters['end_created_at']))
                array_push($rules, ['field' => 'created_at', 'op' => 'le', 'data' => date("Y-m-d 23:59:59", strtotime(str_replace('/', '-', $parameters['end_created_at'])))]);

            if (!empty($rules))
                $condition = ['groupOp' => 'AND', 'rules' => $rules];

            $turnovers = TurnoverService::getInstance()->getList(
                isset($parameters['page']) ? $parameters['page'] : 1,
                isset($parameters['page_size']) ? $parameters['page_size'] : 10,
                isset($parameters['sort']) ? $parameters['sort'] : 'desc',
                isset($parameters['order']) ? $parameters['order'] : 'id',
                $condition
            );

            if (! isset($parameters['from_api']) || $parameters['from_api'] !== true) {

                $turnovers = User::getUsersByModule($turnovers);

                $turnovers = Member::getMembersByModules($turnovers);

                $turnovers = Account::getAccountsByModules($turnovers);
            } else {
                $withdraw_id_arr = array_column($turnovers['data'], 'id');
                if ($get_withdraw_order && !empty($withdraw_id_arr)) {
                    // 查询提现订单列表
                    $withdraw_id_arr = array_filter($withdraw_id_arr);
                    $withdraw_orders = [];
                    if (count($withdraw_id_arr) == 1)
                        $withdraw_orders['data'][] = WithdrawService::getInstance()->getOne(['groupOp' => 'AND', 'rules' => [
                            ['field' => 'turnover_id', 'op' => 'eq', 'data' => implode(',', $withdraw_id_arr)]]]);
                    else if (count($withdraw_id_arr) > 1)
                        $withdraw_orders = WithdrawService::getInstance()->getList(1, count($withdraw_id_arr), 'desc', 'turnover_id',
                            ['groupOp' => 'AND', 'rules' => [
                                ['field' => 'turnover_id', 'op' => 'in', 'data' => implode(',', $withdraw_id_arr)]]]);

                    if ($withdraw_id_arr) {
                        $withdraw_stats_arr = array_column($withdraw_orders['data'], 'stats', 'turnover_id');
                        $withdraw_order_sn_arr = array_column($withdraw_orders['data'], 'sn', 'turnover_id');
                        foreach ($turnovers['data'] as $idx => $turnover_info) {
                            $turnovers['data'][$idx]['withdraw_stats'] = isset($withdraw_stats_arr[$turnover_info['id']]) ?
                                $withdraw_stats_arr[$turnover_info['id']] : '';
                            $turnovers['data'][$idx]['withdraw_order_sn'] = isset($withdraw_order_sn_arr[$turnover_info['id']]) ?
                                $withdraw_order_sn_arr[$turnover_info['id']] : '';
                        }
                    }
                }
            }

            return $turnovers;

        } catch (MemberException $e) {
            throw $e;
        } catch (AccountException $e) {
            throw $e;
        } catch (TurnoverException $e) {
            throw $e;
        } catch (ModelDriverException $e) {
            throw $e;
        } catch (ModelException $e) {
            if ($e->getCode() == ModelException::DATA_NOT_EXISTS_NO)
                throw new TurnoverException(TurnoverException::TURNOVER_IS_NOT_EXISTS, TurnoverException::TURNOVER_IS_NOT_EXISTS_NO);
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    /**
     * 金币、余额互相转换
     * @param array $parameters
     * @throws MemberException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TransformerException
     * @throws TurnoverException
     */
    static public function exchange($parameters = []) {
        try {
            if (! isset($parameters['from_api']) || $parameters['from_api'] !== true)
                throw new TurnoverException(TurnoverException::TURNOVER_DENIED, TurnoverException::TURNOVER_DENIED_NO);

            // 校验type参数
            if (! in_array($parameters['type'], self::EXCHANGE_ALLOWED_TYPE_ARR))
                throw new TurnoverException(TurnoverException::INVALID_OPERATING, TurnoverException::INVALID_OPERATING_NO);

            $member = MemberService::getInstance()->getOne(Registry::get('jwt_info')->id);
            if ($member['stats'] != 1)
                throw new MemberException(MemberException::INVALID_STATS, MemberException::INVALID_STATS_NO);

            if ($member['integral'] - $parameters['amount'] < 0)
                throw new TurnoverException(TurnoverException::INTEGRAL_NOT_ENOUGH, TurnoverException::INTEGRAL_NOT_ENOUGH_NO);

            // 获取系统配置 读取积分与余额的对应值
            /*$coefficient = static::INTEGRAL_TO_BALANCE_COEFFICIENT;
            $balance_incr = $parameters['type'] == 3 ? ($parameters['amount'] * $coefficient) :
                ($parameters['amount'] / $coefficient);*/
            $balance_incr = $parameters['exchange'];

            $insert_arr = [
                // 减少/增加积分
                [
                    'member_id' => $member['id'], 'currency' => $member['integral'],
                    'type' => 2,
                    'amount' => 0 - $parameters['amount'],
                    'remain' => $member['integral'] - $parameters['amount'],
                    'stats' => 1, 'remark' => '金豆转余额的金豆减少记录'
                ],
                // 增加/减少余额
                [
                    'member_id' => $member['id'], 'currency' => $member['balance'],
                    'type' => $parameters['type'],
                    'amount' => $balance_incr,
                    'remain' => $member['balance'] + $balance_incr,
                    'stats' => 1, 'remark' => '金豆转余额的余额增加记录'
                ]
            ];
            TurnoverService::getInstance()->batchInsert($insert_arr);

            $update_arr = [
                'integral' => $insert_arr[0]['remain'],
                'balance' => $insert_arr[1]['remain']
            ];
            MemberService::getInstance()->update($update_arr, $member['id']);

        } catch (MemberException $e) {
            throw $e;
        } catch (TurnoverException $e) {
            throw $e;
        } catch (ModelDriverException $e) {
            throw new TurnoverException(TurnoverException::TURNOVER_CREATE_FAILURE, TurnoverException::TURNOVER_CREATE_FAILURE_NO);
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        }
    }

    /**
     * 发起提现
     * @param array $parameters
     * @return bool
     * @throws MemberException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws TransformerException
     * @throws TurnoverException
     * @throws ServiceException
     */
    static public function withdraw($parameters = []) {
        try {
            if (! isset($parameters['from_api']) || $parameters['from_api'] !== true)
                throw new TurnoverException(TurnoverException::TURNOVER_DENIED, TurnoverException::TURNOVER_DENIED_NO);

            // 校验type参数
            if (! in_array($parameters['type'], self::WITHDRAW_ALLOWED_TYPE_ARR))
                throw new TurnoverException(TurnoverException::INVALID_OPERATING, TurnoverException::INVALID_OPERATING_NO);
            //校验支付密码
            if (! isset($parameters['paypassword']))
                throw new MemberException(MemberException::MEMBER_PASSWORD_EMPTY, MemberException::MEMBER_PASSWORD_EMPTY_NO);
            $member=Member::getMemberInfoById(Registry::get('jwt_info')->id);

            if(!isset($member['pay_password'])||empty($member['pay_password'])){
                throw new MemberException(MemberException::MEMBER_PAY_PASSWORD_EMPTY, MemberException::MEMBER_PAY_PASSWORD_EMPTY_NO);
            }
            if (PwdAss::getInstance(8, true)->CheckPassword($parameters['paypassword'], $member['pay_password']) === false)
                throw new MemberException(MemberException::WRONG_PASSWORD, MemberException::WRONG_PASSWORD_NO);

            $withdraw = TurnoverService::getInstance()->getOne(['groupOp' => 'AND', 'rules' => [
                ['field' => 'member_id', 'op' => 'eq', 'data' => Registry::get('jwt_info')->id],
                ['field' => 'type', 'op' => 'eq', 'data' => 5],
                ['field' => 'created_at', 'op' => 'ge', 'data' => date("Y-m-d 00:00:00", time())],
            ]]);
            if ($withdraw)
                throw new TurnoverException(TurnoverException::WITHDRAW_DAILY_LIMIT, TurnoverException::WITHDRAW_DAILY_LIMIT_NO);

            // 校验提现账号
            $account = AccountService::getInstance()->getOne(['groupOp' => 'AND', 'rules' => [
                ['field' => 'id', 'op' => 'eq', 'data' => $parameters['account_id']],
                ['field' => 'member_id', 'op' => 'eq', 'data' => Registry::get('jwt_info')->id]
            ]]);
            if (empty($account))
                throw new TurnoverException(TurnoverException::WITHDRAW_WITHOUT_ACCOUNT, TurnoverException::WITHDRAW_WITHOUT_ACCOUNT_NO);


            $member = MemberService::getInstance()->getOne(Registry::get('jwt_info')->id);
            if ($member['stats'] != 1)
                throw new MemberException(MemberException::INVALID_STATS, MemberException::INVALID_STATS_NO);

            if ($member['balance'] - $parameters['amount'] < 0)
                throw new TurnoverException(TurnoverException::BALANCE_NOT_ENOUGH, TurnoverException::BALANCE_NOT_ENOUGH_NO);

            $currency = $member['balance'];
            $type = $parameters['type'];
            $remain = $member['balance'] - $parameters['amount'];
            $amount = 0 - $parameters['amount'];
            $remark = '用户申请提现。';

            // $member_id = 0, $account_id = 0, $type = 0, $currency = 0.00, $amount = 0.00, $remain = 0.00, $stats = 0,
            // $remark = "", $created_at = "", $updated_at = "", $updated_by = 0
            $turnover = TurnoverService::getInstance()->create($member['id'], $account['id'], $type, $currency, $amount, $remain, 0, $remark);

            // 扣除会员余额
            MemberService::getInstance()->update(['balance' => $remain], $member['id']);

//            JPush::withdrawPush($turnover['id']);

            return true;

        } catch (MemberException $e) {
            throw $e;
        } catch (TurnoverException $e) {
            throw $e;
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new TurnoverException(TurnoverException::TURNOVER_CREATE_FAILURE, TurnoverException::TURNOVER_CREATE_FAILURE_NO);
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        }
    }

    /**
     * 编辑流水记录
     * @param $parameters
     * @return array|mixed|null
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TransformerException
     * @throws TurnoverException
     */
    static public function editWithdraw($parameters) {
        try {
            if (isset($parameters['from_api']) && $parameters['from_api'] === true)
                throw new TurnoverException(TurnoverException::TURNOVER_DENIED, TurnoverException::TURNOVER_DENIED_NO);

            if (! isset($parameters['id']) || empty($parameters['id']))
                throw new TurnoverException(TurnoverException::TURNOVER_ID_IS_EMPTY, TurnoverException::TURNOVER_ID_IS_EMPTY_NO);

            $update_arr = [];
            if (isset($parameters['stats']) && ! in_array($parameters['stats'], self::TURNOVER_VALID_STATS_ARR)) {
                throw new TurnoverException(TurnoverException::INVALID_STATS, TurnoverException::INVALID_STATS_NO);
            } else if (isset($parameters['stats']) && in_array($parameters['stats'], self::TURNOVER_VALID_STATS_ARR))
                $update_arr['stats'] = $parameters['stats'];

            $turnover = TurnoverService::getInstance()->getOne($parameters['id']);
            if (!empty($update_arr)) {
                $user_info = UserService::getInstance()->getOne(Registry::get('jwt_info')->id);
                $member = MemberService::getInstance()->getOne($turnover['member_id']);

                $update_arr['updated_by'] = Registry::get('jwt_info')->id;
                $update_arr['remark'] = $turnover['remark'] . $user_info['mobile'] . "于" . date("Y-m-d H:i:s", time()) .
                    "完成审核。审核状态为:" . ($parameters['stats'] == 2 ? "拒绝" : ($parameters['stats'] == 1 ? "通过" : "为审核")) . "\r\n";

                $turnover_model = TurnoverModel::getInstance();
                $conn = $turnover_model->getConn();
                $conn->beginTransaction();
                try {
                    $update_sql = "UPDATE `turnover` SET ";
                    foreach ($update_arr as $column_name => $value) {
                        $update_sql .= " `" . $column_name. "` = '" . $value . "',";
                    }
                    $update_sql = substr($update_sql, 0, strrpos($update_sql, ',')) . " WHERE `id` = '" . $parameters['id'] . "'";
                    Registry::get('db_log')->info(($parameters['stats'] == 2 ? "拒绝" : "同意") ."提现: " . $update_sql);
                    $conn->executeQuery($update_sql);


                    if ($update_arr['stats'] == 2) {
                        // 新增一条归还余额的流水记录
                        $sql = "INSERT INTO `turnover` (`type`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                            "VALUE ('4', '1', '拒绝提现，归还余额', '" . $member['balance'] . "', '" . abs($turnover['amount']) . "', '" . ($member['balance'] + abs($turnover['amount'])) . "')";
                        Registry::get('db_log')->info("归还余额sql: " . $sql);
                        $conn->executeQuery($sql);

                        $update_member = "UPDATE `member` SET `balance` = `balance` + " . abs($turnover['amount']) . " WHERE `id` = '" . $member['id'] . "'";
                        Registry::get('db_log')->info("归还member的sql: " . $sql);
                        $conn->executeQuery($update_member);
                    }

                    $conn->commit();
                } catch (\Exception $e) {
                    $conn->rollback();
                    throw new TurnoverException(TurnoverException::TURNOVER_EDIT_FAILURE, TurnoverException::TURNOVER_EDIT_FAILURE_NO);
                }
            }

            return $turnover;
        } catch (TurnoverException $e) {
            throw $e;
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new TurnoverException(TurnoverException::TURNOVER_EDIT_FAILURE, TurnoverException::TURNOVER_EDIT_FAILURE_NO);
            throw $e;
        } catch (ModelException $e) {
            if ($e->getCode() == ModelException::DATA_NOT_EXISTS)
                throw new TurnoverException(TurnoverException::TURNOVER_IS_NOT_EXISTS, TurnoverException::TURNOVER_IS_NOT_EXISTS_NO);
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

}
